#include <iostream>
#include <string>
#include <cstring>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <cerrno>
#include <functional>
#include <wait.h>
#include <stdint.h>
#include "Log.hpp"
#include "Commond.hpp"
#include "ThreadPool.hpp"

#define BACKLOG 8

static const uint16_t gport = 8082;

using namespace LogModule;
using namespace ThreadPoolModule;
class TcpServer
{
private:
    using task_t = std::function<void()>;
    struct ThreadData
    {
        int sockfd;
        TcpServer *self;
    };

public:
    TcpServer(const uint16_t port = gport) : _port(port), _isrunning(false)
    {
    }

    void ServerInit()
    {
        // 1.创建socket
        _listensockfd = ::socket(AF_INET, SOCK_STREAM, 0);
        if (_listensockfd < 0)
        {
            LOG(LogLevel::FATAL) << "sockfd error";
            Die(SOCKET_ERR)
        }

        LOG(LogLevel::INFO) << "sockfd success, sockfd is: " << _listensockfd;

        struct sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_port = ::htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;
        // 2,bind
        int n = ::bind(_listensockfd, CONV(&local), sizeof(local));
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind error";
            Die(BIND_ERR);
        }

        LOG(LogLevel::INFO) << "sockfd success, sockfd is:" << _listensockfd;

        // 3,Tcp是面向连接的，就是要求tcp随时随地等待被连接
        // tcp 需要将socket设置为监听状态
        n = ::listen(_listensockfd, BACKLOG);
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "listen error ";
            Die(LISTEN_ERR);
        }

        LOG(LogLevel::INFO) << "listen success, sockfd is" << _listensockfd;
    }

    void HandlerRequest(int sockfd) // TCP也是全双工的
    {
        LOG(LogLevel::INFO) << "HandlerRequest, sockfd is: " << sockfd;
        char inbuffer[4096];
        // 长任务
        while (true)
        {
            // 约定用户发过来的是一条完整的命令string
            ssize_t n = ::read(sockfd, inbuffer, sizeof(inbuffer)); // 读取是不完善的
            if (n > 0)
            {
                LOG(LogLevel::INFO) << inbuffer;
                inbuffer[n] = 0;
                std::string echo_string = "server echo# ";
                echo_string += inbuffer;

                ::write(sockfd, echo_string.c_str(), echo_string.size()); // 写也是不完善的
                // ::send(sockfd, echo_string.c_str(), sizeof())
            }
            else if (n == 0)
            {
                // read如果读取返回值是0， 表示client退出
                LOG(LogLevel::INFO) << "client quit: " << sockfd;
                break;
            }
            else
            {

                // 读取失败了
                break;
            }
        }
        LOG(LogLevel::INFO) << "Closing sockfd: " << sockfd;
        ::close(sockfd);
    }

    // static void* ThreadEntry(this, void* args)
    // 这里不加static的话, 会有this指针不符合pthread_create()
    // 因为使用static成为了静态，就没有this指针了，但是也同时无法使用调用this指针
    // 然后只能包装结构体调用this指针
    static void *ThreadEntry(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *data = (ThreadData *)args;
        data->self->HandlerRequest(data->sockfd);
        return nullptr;
    }

    void Start()
    {
        _isrunning = true;
        while (true)
        {
            struct sockaddr_in peer;
            socklen_t peerlen = sizeof(peer);
            // 不能和自己直接读取数据
            // 1，获取新链接
            LOG(LogLevel::DEBUG) << "accept ing ...";
            // 我们要获取client的信息：数据（sockfd,）+ client socket信息（accept || recvfrom）
            int sockfd = ::accept(_listensockfd, CONV(&peer), &peerlen);
            if (sockfd < 0)
            {
                LOG(LogLevel::FATAL) << "accept error" << strerror(errno);
                continue;
            }

            // 获取成功了s
            LOG(LogLevel::INFO) << "accept succcess, sockfd is: " << sockfd;
            // version 0
            //  HandlerRequest(sockfd);

            // version1 多线程版本
            //  pid_t id = fork();
            //  if(id == 0)
            //  {
            //      // child
            //      //问题1：子进程继承父进程的文件描述符表两张
            //      //1，关闭不必要的fd
            //      ::close(_listensockfd);
            //      if(fork() > 0) exit(0);//子进程退出
            //      // 孙子进程->孤儿进程->1
            //      HandlerRequest(sockfd);
            //      exit(0);
            //  }
            //  ::close(sockfd);
            //  //不会阻塞
            //  int rid = ::waitpid(id,nullptr, 0);
            //  if(rid < 0)
            //  {
            //      LOG(LogLevel::WARNING) << "waitpid error";
            //  }

            // version2 多线程版本
            //  主线程和新线程是如何看待：文件描述符表，共享一张文件描述表！！
            //  pthread_t tid;
            //  ThreadData* data = new ThreadData;
            //  data->sockfd = sockfd;
            //  data->self = this;
            //  pthread_create(&tid, nullptr,ThreadEntry , data);

            // version-3：线程池版本 比较适合处理短任务，或者用户量少的情况
            task_t f = std::bind(&TcpServer::HandlerRequest, this, sockfd); // 构建任务
            ThreadPool<task_t>::gerInstance()->Equeue([this, sockfd]()
                                                      { this->HandlerRequest(sockfd); });
        }
    }

    void Stop()
    {
        _isrunning = false;
    }

    ~TcpServer()
    {
    }

private:
    int _listensockfd; // 坚听socket
    uint16_t _port;
    bool _isrunning; // 服务器运行状态
};